/*
 * Wiener.cpp
 *
 *  Created on: Nov 26, 2011
 *      Author: igor
 */

#include "Wiener.h"

#include <iostream>
#include <stdio.h>
#include <math.h>

using namespace std;

Wiener::Wiener()
{
}

Wiener::~Wiener(void)
{
}

void Wiener::calculate()
{

	int q1, q2, q3, alfa1, alfa2, alfa3, beta1, beta2, beta3, rem, rem1, rem2;

	rem1 = m_rsaKey.e;
	rem2 = m_rsaKey.N;

	q1 = rem1/rem2;
	rem = rem1%rem2;

	rem1 = rem2;
	rem2 = rem;

	q2 = rem1/rem2;
	rem = rem1%rem2;

	rem1 = rem2;
	rem2 = rem;

	alfa1 = q1;
	alfa2 = q1 * q2+ 1;

	beta1 = 1;
	beta2 = q2;

	if(check(alfa2, beta2))
	{
			m_result.d = beta2;
			m_result.phi = (m_rsaKey.e * m_result.d - 1) / alfa2;
			m_result.succeded = true;
			return;
	}
	m_nK = 2;

	while (rem != 0)
	{
		q3 = rem1/rem2;
		rem = rem1%rem2;

		rem1 = rem2;
		rem2 = rem;

		alfa3 = q3 * alfa2 + alfa1;
		alfa1 = alfa2;
		alfa2 = alfa3;

		beta3 = q3 * beta2 + beta1;
		beta1 = beta2;
		beta2 = beta3;

		if(check(alfa3, beta3))
		{
			m_result.d = beta3;
			m_result.phi = (m_rsaKey.e * m_result.d - 1) / alfa3;
			m_result.succeded = true;
			return;
		}

		m_nK++;
	}
	m_result.succeded = false;

}

bool Wiener::check(const int& k, const int& d)
{
	int b;
	int delta;

	if (k || (m_rsaKey.e * d - 1)){
		b = (m_rsaKey.e * d - 1)/k;
	}
	else{
		return false;
	}

	b = b - m_rsaKey.N - 1;

	if ( (delta = b * b - (4 * m_rsaKey.N)) < 0)
		return false;

	int sqrtDelta = sqrt(delta);

	if ((sqrtDelta*sqrtDelta) != delta){
		return false;
	}

	m_result.p = sqrtDelta - b;
	if (sqrtDelta%2 == 1)
	{
		m_result.p = 0;
		return false;
	}

	m_result.p = m_result.p / 2;
	m_result.q = (-sqrtDelta - b ) / 2;

	return true;

}

Wiener::Result Wiener::attack(PublicKey &key)
{
	m_rsaKey.e = key.e;
	m_rsaKey.N = key.N;
	m_result.succeded = false;

	calculate();

	return m_result;
}
